import React from 'react';
import { get, set, last } from 'lodash-es';
import produce from 'immer';
import showDicesSelector from '../components/dices-selector';
import {
  blueData,
  yellowData,
  initDices,
  greenData,
  orangeData,
  purpleData,
} from './const';
import { drapDices, dividLittle3, findDiceByType } from '../utils';
import { exaction } from './exaction';

export type TypeStore = {
  back: () => void;
  reverseChange: (path: any[], dice: any, value?: any) => void;
  rockDices: () => void;
  beRockDices: () => void;
  nextRound: () => void;
  add1: number;
  reRoll: number;
  round: number;
  blueData: (string | number)[][][];
  yellowData: (string | number)[][][];
  greenData: number[][];
  orangeData: (string | number)[][];
  purpleData: (string | number)[][];
  exaction: any;
  exactions: any[];
  dices: {
    rockPool: any[];
    chosen: any[];
    locked: any[];
  };
};

export type TypeSetStore = React.Dispatch<React.SetStateAction<TypeStore>>;

export const useStore = () => {
  const [store, setStore] = React.useState({
    add1: 0,
    reRoll: 0,
    round: 1,
    blueData,
    yellowData,
    greenData,
    orangeData,
    purpleData,
    exaction: exaction as any,
    exactions: [],
    dices: (initDices as unknown) as {
      rockPool: any[];
      chosen: any[];
      locked: any[];
    },
  });
  const { newSetStore, back } = useHistory(setStore, store);

  useCheck(store, setStore);

  const reverseChange = (path: any[], dice: any, value?: any) => {
    if (!dice.type) {
      console.log('dice error', dice);
      return;
    }
    newSetStore(oldState => {
      return produce(oldState, draft => {
        //设置选择
        const theDice = oldState.dices.rockPool.find(i => i.type === dice.type);

        if (theDice) {
          set(draft, path, value || 1);
          draft.dices.chosen = [...oldState.dices.chosen, theDice];
          draft.dices.locked = [
            ...oldState.dices.locked,
            ...oldState.dices.rockPool.filter(i => i.value < dice.value),
          ];
          draft.dices.rockPool = oldState.dices.rockPool
            .filter(i => i.type !== dice.type)
            .filter(i => i.value > dice.value - 1);
        }
      });
    });
  };

  const rockDices = () => {
    newSetStore(oldState => {
      return produce(oldState, draft => {
        draft.dices.rockPool = drapDices(draft.dices.rockPool);
      });
    });
  };

  const beRockDices = () => {
    newSetStore(oldState => {
      return produce(oldState, draft => {
        const dices = drapDices(initDices.rockPool);
        const { small, large } = dividLittle3(dices);
        draft.dices.rockPool = small;
        draft.dices.locked = large;
      });
    });
  };

  React.useEffect(() => {
    if (store.round === 1 || store.round === 3) {
      newSetStore(oldState => {
        return {
          ...oldState,
          reRoll: oldState.reRoll + 1,
        };
      });
    }
    if (store.round === 2) {
      newSetStore(oldState => {
        return {
          ...oldState,
          add1: oldState.add1 + 1,
        };
      });
    }
    if (store.round === 4) {
      newSetStore(oldState => {
        return {
          ...oldState,
          exactions: [
            ...oldState.exactions,
            {
              type: 'any',
              value: 'any',
            },
          ],
        };
      });
    }
  }, [store.round]);

  const gHandler = ({
    type,
    value,
    path,
    theFirstValue,
  }: {
    type: any;
    path: any[]; //数据对应的路径
    value: any;
    theFirstValue?: any;
  }) => {
    const blueDice = findDiceByType(store.dices, 'blue');
    const whiteDice = findDiceByType(store.dices, 'white');

    const blueDiceUseable = !!store.dices.rockPool.find(d => d.type === 'blue');
    const whiteDiceUseable = !!store.dices.rockPool.find(
      d => d.type === 'white',
    );

    const has1 = blueDiceUseable || whiteDiceUseable;
    const useable =
      !value &&
      has1 &&
      blueDice &&
      whiteDice &&
      blueDice.value + whiteDice.value === theFirstValue;

    return {
      useable,
      handler: async () => {
        if (useable) {
          var dice: any = blueDice || whiteDice;
          if (blueDiceUseable && whiteDiceUseable) {
            dice = await showDicesSelector([blueDice, whiteDice]);
          }
          dice && reverseChange(path, dice);
        }
      },
    };
  };

  return {
    ...store,
    back,
    reverseChange,
    rockDices,
    beRockDices,
    setStore,
    newSetStore,
    gHandler,
    nextRound: () => {
      newSetStore(oldState => {
        return {
          ...oldState,
          round: oldState.round + 1,
          dices: initDices,
        };
      });
    },
  };
};

const useHistory = (setStore: any, store: any) => {
  const history = React.useRef([store]) as { current: any };

  const newSetStore: TypeSetStore = (arg: any) => {
    if (typeof arg === 'function') {
      setStore((old: any) => {
        const cur = arg(old);
        history.current.push(cur);
        return cur;
      });
    } else {
      history.current.push(arg);
      setStore(arg);
    }
  };

  return {
    history,
    newSetStore,
    back: () => {
      history.current.pop();
      const snapShot = last(history.current);
      snapShot && setStore(snapShot);
    },
  };
};

const useCheck = (store: any, setStore: any) => {
  React.useEffect(() => {
    Object.keys(store.exaction).forEach(
      k => {
        if (store.exaction[k]?.check) {
          if (store.exaction[k].check(store) && !store.exaction[k].use) {
            store.exaction[k]?.set &&
              setStore((store: any) => {
                return produce(store, (draft: any) => {
                  store.exaction[k]?.set(draft);
                });
              });
          }
        }
      },
      [store],
    );
  });
};
